// 观察者（判断新值与旧值有没有变化，有就去更新视图）
class Watcher {
  constructor(vm, attr, cb) {
    this.vm = vm
    this.attr = attr
    this.cb = cb
    // 保存旧值
    this.oldVal = this.getOldVal()
  }
  getOldVal() {
    Dep.target = this
    let oldVal = compileUtil.getVal(this.vm, this.attr)
    Dep.target = null
    return oldVal
  }
  update() {
    let newVal = compileUtil.getVal(this.vm, this.attr)
    if (newVal !== this.oldVal) {
      this.cb(newVal) // 回调出去，对应的函数去更新视图
    }
  }
}

// 订阅者（1.收集依赖watcher, 2. 通知观察者更新）
class Dep {
  constructor() {
    this.subs = []
  }
  addSubs(watcher) {
    this.subs.push(watcher)
  }
  notify() {
    //console.log('通知了每一个观察者', this.subs)
    this.subs.forEach( w => {
      w.update()
    })
  }
}

// 观察者(劫持监听数据)
class Observer {
  
  constructor(data) {

    this.observer(data)  
  }
  observer(data={}) {
    if(!data || typeof data !== 'object') {
      return
    }
    // 遍历所有数据
    Object.keys(data).forEach( attr => {
      this.defineReactive(data, attr, data[attr])
    })
  }
  defineReactive(obj, attr, val) {
    // 递归
    this.observer(val)
    const dep = new Dep()
    Object.defineProperty(obj, attr, {
      enumerable: true, // 可修改
      configurable: false, // 可枚举
      get() {
       // 数据变化时，向订阅者添加观察者
        Dep.target && dep.addSubs(Dep.target)
        return val
      },
      set: (newVal) =>{
        this.observer(newVal)
        if (val !== newVal) {
          val = newVal
          // 通知Dep
          dep.notify()
        }
      }
    })
  }
}